In [1]:
import numpy as np
import openpnm as op
np.random.seed(10)
%matplotlib inline
Start by creating a Delaunay network. Because it uses random base points it will better illustrate the process of adding boundary pores to arbitrary networks:
In [2]:
pn = op.network.Delaunay(num_points=200, shape=[1, 1, 0])
print(pn)
As can be seen in the above printout, the Delaunay class predefines many labels including boundaries and sides. In fact, as can be seen in the plot below, the Delaunay class also adds boundary pores to the topology. (Note that the Delaunay network is generated randomly so your's will not look the same, nor have the same number of total pores and throats). In this case, the location of the boundary pores is determined from the Voronoi cell that surrounds each Delaunay point, so the boundary cells apper to be randomly oriented relative to the internal pore they are connected with. In the example that follows, we'll be removing these pores, then adding boundary pores in a manual way.
In [3]:
#NBVAL_IGNORE_OUTPUT
fig = op.topotools.plot_connections(network=pn)
fig = op.topotools.plot_coordinates(network=pn, fig=fig, c='r')
fig.set_size_inches((7, 7))
For the purpose of this tutorial, we will trim these boundary pores from the network since we'll be adding our own.
In [4]:
op.topotools.trim(network=pn, pores=pn.pores('boundary'))
print(pn)
Plotting the network now shows the missing pores. Our goal will be re-add boundary pores to each face.
In [5]:
#NBVAL_IGNORE_OUTPUT
fig = op.topotools.plot_connections(network=pn)
fig = op.topotools.plot_coordinates(network=pn, fig=fig, c='r')
fig.set_size_inches((7, 7))
The topotools
module in OpenPNM provides many handy helper functions for dealing with topology. We'll first use the find_surface_pores
function. It works be specifying the location of a set of marker points outside the domain, then performing a Delaunay tessellation between these markers and the network pores. Any pores that form a simplex with the marker points are considered to be on the surface. By default OpenPNM will place one marker on each edge of the domain in an attempt to find all the surfaces. In our case, we will specify them manually to only find one face.
Specifying the markers can be a challenge. If we only specify a single marker, we will only find a limited number of surface pores due to the way the triangulation works.
In [6]:
#NBVAL_IGNORE_OUTPUT
markers = np.array([[-0.1, 0.5]])
op.topotools.find_surface_pores(network=pn, markers=markers, label='left_surface')
fig = op.topotools.plot_connections(network=pn)
fig = op.topotools.plot_coordinates(network=pn, pores=pn.pores('left_surface'), fig=fig, c='r')
fig.set_size_inches((7, 7))
As can be seen, some of the pores in deeper recesses of the surface were not found by this method. If we want to be certain of finding all the surface pores on the left side of the domain we can add more markers:
In [7]:
#NBVAL_IGNORE_OUTPUT
markers = np.array([[-0.1, 0.2], [-0.1, 0.4], [-0.1, 0.6], [-0.1, 0.8]])
op.topotools.find_surface_pores(network=pn, markers=markers, label='left_surface')
fig = op.topotools.plot_connections(network=pn)
fig = op.topotools.plot_coordinates(network=pn, pores=pn.pores('left_surface'), fig=fig, c='r')
fig.set_size_inches((7, 7))
Now we've captured several more pores. In some cases we may actually get more than we wanted, including some that are more correctly on the bottom of the domain. This is why finding surfaces requires a careful touch, although this problem becomes less important in domains with more pores.
Next we want to take the newly labeled surface pores and 'clone' them. This creates new pores in the network that are physically located in the same place as their 'parents'. They are also connected only to their 'parents' by default which is what we want, though this can be changed using the mode
argument. In the following code, we tell the function to clone the 'left_surface' pores and to give them a new label of 'left_boundary'.
In [8]:
op.topotools.clone_pores(network=pn, pores=pn.pores('left_surface'), labels=['left_boundary'])
Now that we've cloned the pores, we need to move them. In this case we want them to all site on teh x=0 boundary face. We can do this by directly altering the 'pore.coords' array:
In [9]:
Ps = pn.pores('left_boundary')
coords = pn['pore.coords'][Ps]
coords *= [0, 1, 1]
pn['pore.coords'][Ps] = coords
print(pn)
The above code will set the x-coordinate of each of the cloned pores to 0, while maintaining the other coordinates the same. The result is:
In [10]:
#NBVAL_IGNORE_OUTPUT
fig = op.topotools.plot_connections(network=pn)
fig = op.topotools.plot_coordinates(network=pn, pores=pn.pores('left_surface'), fig=fig, c='r')
fig = op.topotools.plot_coordinates(network=pn, pores=pn.pores('left_boundary'), fig=fig, c='g')
fig.set_size_inches((7, 7))